package com.moonLight.weblog.web.service.Impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.moonLight.weblog.admin.event.ReadArticleEvent;
import com.moonLight.weblog.common.domain.dos.*;
import com.moonLight.weblog.common.domain.mapper.*;
import com.moonLight.weblog.common.enums.ResponseCodeEnum;
import com.moonLight.weblog.common.exception.BizException;
import com.moonLight.weblog.common.utils.PageResponse;
import com.moonLight.weblog.common.utils.Response;
import com.moonLight.weblog.web.convert.ArticleConvert;
import com.moonLight.weblog.web.markdown.MarkdownHelper;
import com.moonLight.weblog.web.model.vo.article.*;
import com.moonLight.weblog.web.model.vo.category.FindCategoryListRspVO;
import com.moonLight.weblog.web.model.vo.tag.FindTagListRspVO;
import com.moonLight.weblog.web.service.ArticleService;
import com.moonLight.weblog.web.utils.MarkdownStatsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.YearMonth;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private TArticleMapper articleMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private TArticleCategoryMapper articleCategoryMapper;
    @Autowired
    private TArticleContentMapper articleContentMapper;
    @Autowired
    private TagMapper tagMapper;
    @Autowired
    private TArticleTagMapper articleTagRelMapper;
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    /**
     * 从数据库 把数据全部拿到内存中
     * 由java进行筛选工作
     * 耗时:耗时: 481ms
     * @param findIndexArticlePageListReqVO
     * @return
     */
    @Override
    public Response findArticlePageList(FindIndexArticlePageListReqVO findIndexArticlePageListReqVO) {
        Long current = findIndexArticlePageListReqVO.getCurrent();
        Long size = findIndexArticlePageListReqVO.getSize();

        // 第一步：分页查询文章主体记录
        Page<TArticleDo> articleDOPage = articleMapper.selectPageList(current, size, null, null, null,null);

        // 返回的分页数据
        List<TArticleDo> articleDOS = articleDOPage.getRecords();

        List<FindIndexArticlePageListRspVO> vos = null;
        if (!CollectionUtils.isEmpty(articleDOS)) {
            // 文章 DO 转 VO
            vos = articleDOS.stream()
                    .map(articleDO -> {
                        FindIndexArticlePageListRspVO vo = ArticleConvert.INSTANCE.convertDO2VO(articleDO);
                        vo.setIsTop(articleDO.getWeight() > 0); // 是否置顶
                        return vo;
                    }).collect(Collectors.toList());

            // 拿到所有文章的 ID 集合
            List<Long> articleIds = articleDOS.stream().map(TArticleDo::getId).collect(Collectors.toList());

            // 第二步：设置文章所属分类
            // 查询所有分类
            List<CategoryDO> categoryDOS = categoryMapper.selectList(Wrappers.emptyWrapper());
            // 转 Map, 方便后续根据分类 ID 拿到对应的分类名称
            Map<Long, String> categoryIdNameMap = categoryDOS.stream().collect(Collectors.toMap(CategoryDO::getId, CategoryDO::getName));

            // 根据文章 ID 批量查询所有关联记录
            List<TArticleCategoryRelDo> articleCategoryRelDOS = articleCategoryMapper.selectByArticleIds(articleIds);

            vos.forEach(vo -> {
                Long currArticleId = vo.getId();
                // 过滤出当前文章对应的关联数据
                Optional<TArticleCategoryRelDo> optional = articleCategoryRelDOS.stream().filter(rel -> Objects.equals(rel.getArticleId(), currArticleId)).findAny();

                // 若不为空
                if (optional.isPresent()) {
                    TArticleCategoryRelDo articleCategoryRelDO = optional.get();
                    Long categoryId = articleCategoryRelDO.getCategoryId();
                    // 通过分类 ID 从 map 中拿到对应的分类名称
                    String categoryName = categoryIdNameMap.get(categoryId);

                    FindCategoryListRspVO findCategoryListRspVO = FindCategoryListRspVO.builder()
                            .id(categoryId)
                            .name(categoryName)
                            .build();
                    // 设置到当前 vo 类中
                    vo.setCategory(findCategoryListRspVO);
                }
            });

            // 第三步：设置文章标签
            // 查询所有标签
            List<TagDO> tagDOS = tagMapper.selectList(Wrappers.emptyWrapper());
            // 转 Map, 方便后续根据标签 ID 拿到对应的标签名称
            Map<Long, String> mapIdNameMap = tagDOS.stream().collect(Collectors.toMap(TagDO::getId, TagDO::getName));

            // 拿到所有文章的标签关联记录
            List<TArticleTagRelDo> articleTagRelDOS = articleTagRelMapper.selectByArticleIds(articleIds);
            vos.forEach(vo -> {
                Long currArticleId = vo.getId();
                // 过滤出当前文章的标签关联记录
                List<TArticleTagRelDo> articleTagRelDOList = articleTagRelDOS.stream().filter(rel -> Objects.equals(rel.getArticleId(), currArticleId)).collect(Collectors.toList());

                List<FindTagListRspVO> findTagListRspVOS = Lists.newArrayList();
                // 将关联记录 DO 转 VO, 并设置对应的标签名称
                articleTagRelDOList.forEach(articleTagRelDO -> {
                    Long tagId = articleTagRelDO.getTagId();
                    String tagName = mapIdNameMap.get(tagId);

                    FindTagListRspVO findTagListRspVO = FindTagListRspVO.builder()
                            .id(tagId)
                            .name(tagName)
                            .build();
                    findTagListRspVOS.add(findTagListRspVO);
                });
                // 设置转换后的标签数据
                vo.setTags(findTagListRspVOS);
            });
        }
        return PageResponse.success(articleDOPage, vos);
    }

    /**
     * 获取文章归档分页数据
     *
     * @param findArchiveArticlePageListReqVO
     * @return
     */
    @Override
    public Response findArchivePageList(FindArchiveArticlePageListReqVO findArchiveArticlePageListReqVO) {
        Long current = findArchiveArticlePageListReqVO.getCurrent();
        Long size = findArchiveArticlePageListReqVO.getSize();

        // 分页查询
        IPage<TArticleDo> page = articleMapper.selectPageList(current, size, null, null, null,null);
        List<TArticleDo> articleDOS = page.getRecords();

        List<FindArchiveArticlePageListRspVO> vos = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(articleDOS)) {
            // DO 转 VO
            List<FindArchiveArticleRspVO> archiveArticleRspVOS =  articleDOS.stream()
                    .map(articleDO -> ArticleConvert.INSTANCE.convertDO2ArchiveArticleVO(articleDO))
                    .collect(Collectors.toList());

            // 按创建的月份进行分组
            Map<YearMonth, List<FindArchiveArticleRspVO>> map = archiveArticleRspVOS.stream()
                    .collect(Collectors.groupingBy(FindArchiveArticleRspVO::getCreateMonth));
            // 使用 TreeMap 按月份倒序排列
            Map<YearMonth, List<FindArchiveArticleRspVO>> sortedMap = new TreeMap<>(Collections.reverseOrder());
            sortedMap.putAll(map);

            // 遍历排序后的 Map，将其转换为归档 VO
            sortedMap.forEach(
                    (k, v) -> vos.add(
                            FindArchiveArticlePageListRspVO.builder().month(k).articles(v).build()
                    )
            );
        }

        return PageResponse.success(page, vos);
    }


    /**
     * 获取文章详情
     *
     * @param findArticleDetailReqVO
     * @return
     */
    @Override
    public Response findArticleDetail(FindArticleDetailReqVO findArticleDetailReqVO) {
        Long articleId = findArticleDetailReqVO.getArticleId();

        TArticleDo articleDO = articleMapper.selectById(articleId);

        // 判断文章是否存在
        if (Objects.isNull(articleDO)) {
            log.warn("==> 该文章不存在, articleId: {}", articleId);
            throw new BizException(ResponseCodeEnum.ARTICLE_NOT_FOUND);
        }

        // 查询正文
        TArticleContentRelDo articleContentDO = articleContentMapper.selectByArticleId(articleId);
        String content = articleContentDO.getContent();
        // 计算 md 正文字数
        Integer totalWords = MarkdownStatsUtil.calculateWordCount(content);

        // DO 转 VO
        FindArticleDetailRspVO vo = FindArticleDetailRspVO.builder()
                .title(articleDO.getTitle())
                .createTime(articleDO.getCreateTime())
                //此处将 markdown 转换为 html
                .content(MarkdownHelper.convertMarkdown2Html(articleContentDO.getContent()))
                .readNum(Long.valueOf(articleDO.getReadNum()))
                .totalWords(totalWords)
                .updateTime(articleDO.getUpdateTime())
                .readTime(MarkdownStatsUtil.calculateReadingTime(totalWords))
                .build();

        log.warn("==> 文章详情MD: {}",articleContentDO.getContent());
        log.warn("==> 文章详情HTml: {}", vo.getContent());
        // 查询所属分类
        TArticleCategoryRelDo articleCategoryRelDO = articleCategoryMapper.selectByArticleId(articleId);
        CategoryDO categoryDO = categoryMapper.selectById(articleCategoryRelDO.getCategoryId());
        vo.setCategoryId(categoryDO.getId());
        vo.setCategoryName(categoryDO.getName());

        // 查询标签
        List<TArticleTagRelDo> articleTagRelDOS = articleTagRelMapper.selectByArticleId(articleId);
        List<Long> tagIds = articleTagRelDOS.stream().map(TArticleTagRelDo::getTagId).collect(Collectors.toList());
        List<TagDO> tagDOS = tagMapper.selectByIds(tagIds);

        // 标签 DO 转 VO
        List<FindTagListRspVO> tagVOS = tagDOS.stream()
                .map(tagDO -> FindTagListRspVO.builder().id(tagDO.getId()).name(tagDO.getName()).build())
                .collect(Collectors.toList());
        vo.setTags(tagVOS);

        // 上一篇
        TArticleDo preArticleDO = articleMapper.selectPreArticle(articleId);
        if (Objects.nonNull(preArticleDO)) {
            FindPreNextArticleRspVO preArticleVO = FindPreNextArticleRspVO.builder()
                    .articleId(preArticleDO.getId())
                    .articleTitle(preArticleDO.getTitle())
                    .build();
            vo.setPreArticle(preArticleVO);
        }

        // 下一篇
        TArticleDo nextArticleDO = articleMapper.selectNextArticle(articleId);
        if (Objects.nonNull(nextArticleDO)) {
            FindPreNextArticleRspVO nextArticleVO = FindPreNextArticleRspVO.builder()
                    .articleId(nextArticleDO.getId())
                    .articleTitle(nextArticleDO.getTitle())
                    .build();
            vo.setNextArticle(nextArticleVO);
        }
        //返回数据之前 开启阅读数+1的事件的发布 交给对应的监听器去实现监听
        eventPublisher.publishEvent(new ReadArticleEvent(this, articleId));


        return Response.success(vo);
    }




}







    /**
     * 自己实现的耗时432ms SQL链接查询次数多
     * 分页查询 可以按照条件查询
     * 1.将 article 表的数据查询出来集合
     * 2.集合遍历 分批查询出 category 和 tag
     * @param findIndexArticlePageListReqVO
     * @return
     */
    //@Override
//    public Response findArticlePageListV1(FindIndexArticlePageListReqVO findIndexArticlePageListReqVO) {
//        Long current = findIndexArticlePageListReqVO.getCurrent();
//        Long size = findIndexArticlePageListReqVO.getSize();
//        Page<TArticleDo> tArticleDoPage = articleMapper.selectPageList(current, size, null, null, null);
//        List<TArticleDo> tArticleRecords = tArticleDoPage.getRecords();
//
//        List<FindIndexArticlePageListRspVO> vos =  new ArrayList<>();
//        if (!CollectionUtils.isEmpty(tArticleRecords)){
//            tArticleRecords.forEach(
//                    tArticleDo -> {
//                        //构建返回类型 Do 转Vo
//                        FindIndexArticlePageListRspVO findIndexArticlePageListRspVO = ArticleConvert.INSTANCE.convertDO2VO(tArticleDo);
//
//                        //关联表中查询出文章对应的分类
//                        TArticleCategoryRelDo tArticleCategoryRelDo = articleCategoryMapper.selectByArticleId(tArticleDo.getId());
//                        Long categoryId = tArticleCategoryRelDo.getCategoryId();
//                        if (Objects.nonNull(categoryId)){
//                            CategoryDO categoryDO = categoryMapper.selectById(categoryId);
//                            FindCategoryListRspVO findCategoryListRspVO = FindCategoryListRspVO.builder().id(categoryDO.getId()).name(categoryDO.getName()).build();
//                            findIndexArticlePageListRspVO.setCategory(findCategoryListRspVO);
//                        }else{
//                            log.warn("文章没有关联分类 分类iD为{}", categoryId);
//                            throw new BizException( ResponseCodeEnum. CATEGORY_NOT_EXISTED);
//                        }
//                        //查询文章对应的标签类
//                        List<TArticleTagRelDo> tArticleTagRelDos = articleTagRelMapper.selectByArticleId(tArticleDo.getId());
//                        List<FindTagListRspVO> tags = new ArrayList<>();
//                        if (!CollectionUtils.isEmpty(tArticleTagRelDos)){
//                            tArticleTagRelDos.forEach(tArticleTagRelDo -> {
//                                FindTagListRspVO findTagListRspVO = new FindTagListRspVO();
//                                Long tagId = tArticleTagRelDo.getTagId();
//                                TagDO tagDO = tagMapper.selectById(tagId);
//                                findTagListRspVO.setId(tagId);
//                                findTagListRspVO.setName(tagDO.getName());
//                                tags.add(findTagListRspVO);
//                            });
//                        }else{
//                            log.warn("文章没有关联标签 对应文章iD为{}", tArticleDo.getId());
//                        }
//                        findIndexArticlePageListRspVO.setTags(tags);
//                        vos.add(findIndexArticlePageListRspVO);
//                    }
//            );
//        }
//        return Response.success(vos);
//    }

